#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define SERIALIZE_OVERHEAD 2

char* deserialize_DNS_name(const unsigned char* input_buf, unsigned short input_buf_size, unsigned short* size_read){
	if(input_buf == NULL || size_read == NULL){
		printf("deserialize_DNS_name: null pointers passed for name or current position\n");
		return NULL;
	}
		
	*size_read = 0;
	//Verification loop could be avoided by using realloc
	unsigned short tmp = (*size_read);
	while(input_buf[tmp] != 0){
		if(input_buf[tmp] & 0xC0){
			printf("deserialize_DNS_name: Using pointers in compressed names, deserialization does not handle this case (%02x)\nCheck if the parameter is the correct pointer\n",input_buf[tmp]);
			return NULL;
		}
		tmp += input_buf[tmp]+1;
		if(tmp > input_buf_size){
			printf("deserialize_DNS_name: name extends outside of the given array size (attempted pos %d, input size %d)\n",tmp,input_buf_size);
			return NULL;
		}
	}

	unsigned short size = tmp;
	
	if(size == 0){
		printf("deserialize_DNS_name: name size is zero. Please check the parameters (pointer to input buffer).\n");
		return NULL;
	}
	
	char* deserialized_name = malloc(size);
	if(deserialized_name == NULL){
		printf("deserialize_DNS_name: could not allocate memory for name\n");
		return NULL;
	}

	tmp = (*size_read);
	unsigned short crtname = 0;
	while(input_buf[tmp] != 0){
		tmp += input_buf[tmp]+1;
		if(crtname >= size-1){
			printf("deserialize_DNS_name: error in parsing name, writing more than allocated string (crtname %d, size %d)\n",crtname,size);
			free(deserialized_name);
			return NULL;
		}
		memcpy(deserialized_name+crtname,input_buf+(*size_read)+1,tmp-(*size_read)-1);
		crtname += tmp-(*size_read)-1;
		deserialized_name[crtname] = '.';
		crtname++;
		*size_read = tmp;
	}

	deserialized_name[size-1] = '\0';
	(*size_read)++;
	
	return deserialized_name;
}


int serialize_DNS_name(unsigned char* output_buf, unsigned short output_buf_size, unsigned short* size_written, const char* name){
	if(output_buf == NULL || size_written == NULL || name == NULL){
		printf("serialize_DNS_name: null parameters\n");
		return 0;
	}
	
	if(strlen(name)+SERIALIZE_OVERHEAD >= output_buf_size){
		printf("serialize_DNS_name: too large string name parameter (size %d) for the remaining size (%d) and also need %d extra characters\n",strlen(name),output_buf_size, SERIALIZE_OVERHEAD);
		return 0;
	}
	
	if(name[0] == '.'){
		printf("serialize_DNS_name: not a legal name (starting with '.')\n");
		return 0;
	}

	(*size_written) = 0;
		
	unsigned short last = 0, tmp = 0;
	for(tmp = 0; tmp < strlen(name); tmp++){
		if(tmp-last >= 0x3F){
			printf("serialize_DNS_name: segment too large in the dns name (from pos %d to %d, max is %d)\n",last,tmp,0x3F);
			return 0;			
		}
		if(name[tmp] == '.'){
			//witing the size	
			output_buf[(*size_written)++] = tmp-last;
			while(last < tmp){
				output_buf[(*size_written)++] = name[last];
				last++;
			}
			last = tmp+1;
			if(tmp < strlen(name)-1 && name[tmp+1] == '.'){
				printf("serialize_DNS_name: invalid DNS name to serialize with two consecutive '.' characters\n");
				return 0;
			}
		}
	}
	//tmp == strlen(name)
	output_buf[(*size_written)++] = tmp-last;
	while(last < tmp){
		if(name[last] != '.')
			output_buf[(*size_written)++] = name[last];
		last++;
	}
	if(name[strlen(name)-1] != '.') //do not encode the last dot
		output_buf[(*size_written)++] = 0;
	else
		output_buf[(*size_written)-1] = 0;
	
	return 1;
}

